/*************************************************************************
 *
 * obsluhy handleru prikazu seriove komunikace
 * 
 * (c) Ales Povalac, alpov@alpov.net, http://www.alpov.net/
 * 
 *************************************************************************
 *
 * $Id: serial_hnds.c 86 2006-09-01 11:11:46Z alpov $
 * 
 *************************************************************************/         

#include <string.h>
#include <avr/io.h>
#include "../avrx/avrx.h"
#include "../avrx/AvrXFifo.h"
#include "serial.h"
#include "serial_hnds.h"
#include "data.h"
#include "sensor.h"
#include "log.h"
#include "dataflash.h"
#include "1wire.h"
#include "pwrman.h"
#include "io.h"


/*************************************************************************
 * obsluha prikazu STDATA_READ
 *************************************************************************/ 
void STDATA_R_Handler(PACKET_HEADER *ph)
{
    void *buffer;
    unsigned char cpy_len;
    
    if (AvrXTestSemaphore(&SensorReady) != SEM_DONE)
        return;
    
    AvrXSetSemaphore(&SensorReady);
    
    if (ph->item_hi == ITEM_TEMPERATURE) {
        buffer = &stdata.temperature;
        cpy_len = sizeof(stdata.temperature);
    }
    else if (ph->item_hi == ITEM_STATE) {
        buffer = &stdata.state;
        cpy_len = sizeof(stdata.state);
    }
    else if (ph->item_hi == ITEM_ALL) {
        buffer = &stdata;
        cpy_len = sizeof(stdata);
    }
    else
        return;
    
    ph->dest = ph->src;
    ph->src = ADDR_SERVER;
    ph->cmd = CMD_STDATA_WRITE;
    SerialSendPacket(ph, buffer, cpy_len, 1);
}


/*************************************************************************
 * obsluha prikazu RWDATA_WRITE
 *************************************************************************/ 
void RWDATA_W_Handler(PACKET_HEADER *ph, char *data, unsigned char length)
{
    void *buffer;
    unsigned char cpy_len;
    
    if (ph->item_hi == ITEM_MODE) {
        buffer = &rwdata.mode;
        cpy_len = sizeof(rwdata.mode);
    }
    else if (ph->item_hi == ITEM_SHIFT) {
        buffer = &rwdata.shift;
        cpy_len = sizeof(rwdata.shift) + sizeof(rwdata.shift_length);
    }
    else if (ph->item_hi == ITEM_SWITCH) {
        buffer = &rwdata.sw_mode;
        cpy_len = sizeof(rwdata.sw_mode) + sizeof(rwdata.sw_datetime);
    }
    else if (ph->item_hi == ITEM_RTC) {
        buffer = &rwdata.now;
        cpy_len = sizeof(rwdata.now);
    }
    else if (ph->item_hi == ITEM_ALL) {
        buffer = &rwdata;
        cpy_len = sizeof(rwdata);
    }
    else
        return;
    
    if (cpy_len != length)
        return;
    
    memcpy(buffer, data, cpy_len);                  // zapsat udaj

    if (ph->dest != ADDR_BROADCAST)
        SerialSendAck(ph);                          // potvrdit, pokud neni broadcast
    
    Serial_STDATA_W(ph->item_hi);                   // zaslat vsem zmenu
}


/*************************************************************************
 * obsluha prikazu RWDATA_READ
 *************************************************************************/ 
void RWDATA_R_Handler(PACKET_HEADER *ph)
{
    void *buffer;
    unsigned char cpy_len;
    
    if (ph->item_hi == ITEM_MODE) {
        buffer = &rwdata.mode;
        cpy_len = sizeof(rwdata.mode);
    }
    else if (ph->item_hi == ITEM_SHIFT) {
        buffer = &rwdata.shift;
        cpy_len = sizeof(rwdata.shift) + sizeof(rwdata.shift_length);
    }
    else if (ph->item_hi == ITEM_SWITCH) {
        buffer = &rwdata.sw_mode;
        cpy_len = sizeof(rwdata.sw_mode) + sizeof(rwdata.sw_datetime);
    }
    else if (ph->item_hi == ITEM_RTC) {
        buffer = &rwdata.now;
        cpy_len = sizeof(rwdata.now);
    }
    else if (ph->item_hi == ITEM_ALL) {
        buffer = &rwdata;
        cpy_len = sizeof(rwdata);
    }
    else
        return;
    
    ph->dest = ph->src;
    ph->src = ADDR_SERVER;
    ph->cmd = CMD_RWDATA_WRITE;
    SerialSendPacket(ph, buffer, cpy_len, 1);
}


/*************************************************************************
 * obsluha prikazu LOG_READ
 *************************************************************************/ 
void LOG_R_Handler(PACKET_HEADER *ph)
{
    char buffer[DF_LOG_PAGESIZE];
    unsigned int i;
    
    ph->dest = ph->src;
    ph->src = ADDR_SERVER;
    ph->cmd = CMD_LOG_WRITE;
    
    AvrXWaitSemaphore(&DataFlashMutex);
    Page_To_Buffer(FlashToBuf2Transfer, ph->item);
    for (i = 0; i < PageSizeNorm; i += sizeof(buffer)) {
        Buffer_Read(Buf2Read, i, sizeof(buffer), buffer);
        SerialSendPacket(ph, buffer, sizeof(buffer), 1);
    }
    AvrXSetSemaphore(&DataFlashMutex);
}


/*************************************************************************
 * obsluha prikazu LOG_ERASE
 *************************************************************************/ 
void LOG_E_Handler(PACKET_HEADER *ph)
{
    LogEraseAll();      // trva cca 2 sekundy
    SerialSendAck(ph);
}


/*************************************************************************
 * obsluha prikazu ONEWIRE SCAN
 *************************************************************************/ 
void ONEWIRE_SCAN_Handler(PACKET_HEADER *ph)
{
    struct {
        char rom[8];
        int temperature;
    } s;
    char result;
    
    ph->dest = ph->src;
    ph->src = ADDR_SERVER;
    memset(&s, 0, sizeof(s));
    
    AvrXWaitSemaphore(&OneWireMutex);
    result = OWFirst(s.rom);
    while (result == OW_FOUND) {
        OWReadTemperature(s.rom, &s.temperature);
        SerialSendPacket(ph, (char*)(&s), sizeof(s), 1);
        result = OWNext(s.rom);
    }
    AvrXSetSemaphore(&OneWireMutex);
}


/*************************************************************************
 * obsluha prikazu POWER_STATUS
 *************************************************************************/ 
void POWER_STATUS_Handler(PACKET_HEADER *ph)
{
    struct {
        unsigned char ext_power;
        unsigned int batt_voltage;
        unsigned int ext_voltage;
    } s;
    
    ph->dest = ph->src;
    ph->src = ADDR_SERVER;
    memset(&s, 0, sizeof(s));
    
    s.ext_power = power_present;
    s.batt_voltage = ReadVoltage(ADC_MUX_BATT);
    s.ext_voltage = ReadVoltage(ADC_MUX_EXT);
    
    SerialSendPacket(ph, (char*)(&s), sizeof(s), 1);
}


/*************************************************************************
 * obsluha prikazu DEBUG
 *************************************************************************/ 
void DEBUG_Handler(PACKET_HEADER *ph)
{
    unsigned char s = ReadOpto();
    
    ph->dest = ph->src;
    ph->src = ADDR_SERVER;
    SerialSendPacket(ph, (char*)(&s), sizeof(s), 1);
}


